﻿using System;
using UnityEngine;
using UnityEngine.EventSystems;

namespace Core
{
    public class PointerDragListener : MonoBehaviour,
        IPointerDownHandler,
        IPointerUpHandler
    {
        public event Action<Vector3> OnDown;
        public event Action<Vector3> OnUp;
        public event Action<Vector3> OnClick;

        public event Action<Vector3> OnBeginDrag;
        public event Action<Vector3> OnDrag;
        public event Action<Vector3> OnEndDrag;


        private bool isDown = false;
        private bool isDrag = false;

        private Vector3 downPos;
        private Vector3 currPos;
        private Vector3 lastPos;


        public static PointerDragListener Get(GameObject go)
        {
            return go.GetComponent<PointerDragListener>() ??
                   go.AddComponent<PointerDragListener>();
        }

        public static PointerDragListener Get(UIWidget widget)
        {
            return Get(widget.gameObject);
        }

        public void OnPointerDown(PointerEventData eventData)
        {
            if (isDown)
            {
                return;
            }

            OnDownHandler();
        }

        public void OnPointerUp(PointerEventData eventData)
        {
            if (isDown == false)
            {
                return;
            }

            OnUpHandler();
        }

        public void Update()
        {
            if (isDown == false)
            {
                return;
            }

            currPos = Input.mousePosition;

            if (isDrag == false)
            {
                var dis = Vector3.Distance(currPos, downPos);
                if (dis > 0)
                {
                    //Debug.LogError($"dis = {dis}");
                }

                if (Vector3.Distance(currPos, downPos) > 1)
                {
                    OnBeginDragHandler();
                }
            }
            else
            {
                if (currPos != lastPos)
                {
                    OnDragHandler();
                }
            }
        }

        private void OnDownHandler()
        {
            downPos = Input.mousePosition;
            currPos = downPos;
            lastPos = downPos;

            isDown = true;

            OnDown?.Invoke(currPos);
        }


        private void OnUpHandler()
        {
            isDown = false;
            currPos = Input.mousePosition;
            OnUp?.Invoke(currPos);
            if (isDrag == false)
            {
                OnClickHandler();
            }
            else
            {
                OnEndDragHandler();
            }
        }

        private void OnClickHandler()
        {
            OnClick?.Invoke(currPos);
        }

        private void OnBeginDragHandler()
        {
            isDrag = true;

            OnBeginDrag?.Invoke(currPos);

            OnDragHandler();
        }

        private void OnDragHandler()
        {
            lastPos = currPos;

            OnDrag?.Invoke(currPos);
        }

        private void OnEndDragHandler()
        {
            isDrag = false;

            OnEndDrag?.Invoke(currPos);
        }
    }
}